---
id: login
title: Login Flow
---

import useBaseUrl from '@docusaurus/useBaseUrl'
import Mermaid from '@theme/Mermaid'
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

OAuth2 and OpenID Connect require an authenticated End-User session for all
OAuth2 / OpenID Connect flows except the `client_credentials` flow which does
not involve End-Users.

ORY Hydra does not contain a database with End-Users but instead uses HTTP
Redirection to "delegate" the login flow to another app - we call this the Login
& Consent App.

The following short video shows the flow from an End-User's perspective - it
includes both login and consent.

<iframe
  width="560"
  height="315"
  src="https://www.youtube.com/embed/txUmfORzu8Y"
  frameborder="0"
  allowfullscreen
></iframe>

The following sequence diagram describes the different API calls and HTTP
Redirects when performing the OAuth2 flow:

<Mermaid
  chart={`sequenceDiagram
    OAuth2 Client->>ORY Hydra: Initiates OAuth2 Authorize Code or Implicit Flow
    ORY Hydra-->>ORY Hydra: No end user session available (not authenticated)
    ORY Hydra->>Login Endpoint: Redirects end user with login challenge
    Login Endpoint-->ORY Hydra: Fetches login info
    Login Endpoint-->>Login Endpoint: Authenticates user with credentials
    Login Endpoint-->ORY Hydra: Transmits login info and receives redirect url with login verifier
    Login Endpoint->>ORY Hydra: Redirects end user to redirect url with login verifier
    ORY Hydra-->>ORY Hydra: First time that client asks user for permissions
    ORY Hydra->>Consent Endpoint: Redirects end user with consent challenge
    Consent Endpoint-->ORY Hydra: Fetches consent info (which user, what app, what scopes)
    Consent Endpoint-->>Consent Endpoint: Asks for end user's permission to grant application access
    Consent Endpoint-->ORY Hydra: Transmits consent result and receives redirect url with consent verifier
    Consent Endpoint->>ORY Hydra: Redirects to redirect url with consent verifier
    ORY Hydra-->>ORY Hydra: Verifies grant
    ORY Hydra->>OAuth2 Client: Transmits authorization code/token`}
/>

## Initiating the OAuth 2.0 / OpenID Connect Flow

The OAuth2 2.0 / OpenID Connect Flow is initiated by pointing the End-User's
browser to the `/oauth2/auth` endpoint. Depending on which flow ("Authorize Code
Flow", "Implicit Flow", ...) you want to use some of the query parameters (e.g.
`/oauth2/auth?response_type=code`, `/oauth2/auth?response_type=token`, ...)
might change but the overall initiation works always by sending the browser to
that URL.

:::note

This guide uses URLs from the [5 Minute Tutorial](../5min-tutorial):

- ORY Hydra Public Endpoint: http://127.0.0.1:4444
- ORY Hydra Admin Endpoint: http://127.0.0.1:4445

When translating this guide into your own environment, make sure to use the
correct endpoint for your interactions.

:::

<Tabs
  defaultValue="ui"
  values={[
    {label: 'UI', value: 'ui'},
    {label: 'HTML', value: 'html'},
    {label: 'JavaScript', value: 'js'},
  ]}>
<TabItem value="ui">
<img src={useBaseUrl('/img/docs/oauth2-consumer.png')}/>
</TabItem>
<TabItem value="html">

```html
<a
  href="https://<hydra-public>/oauth2/auth?client_id=...&response_type=...&scope=..."/>
Login in with ORY Hydra</a>
```

</TabItem>
<TabItem value="js">

```js
// ...
window.location.href =
  'https://<hydra-public>/oauth2/auth?client_id=...&response_type=...&scope=...'
```

</TabItem>
</Tabs>

## Redirection to the Login Endpoint

The next task for ORY Hydra is to know the user of the request. To achieve that,
ORY Hydra checks if a session cookie is set containing information about a
previously successful login. Additionally, OpenID Connect parameters
`id_token_hint`, `prompt`, and `max_age` are evaluated and processed. Depending
on their values and the login state, the user might need to re-authenticate or
the flow will fail completely.

To authenticate the user (this happens regardless of whether a session exists
for the user or not), ORY Hydra redirects the browser to the "Login Endpoint"
established in your config:

```yaml title="hydra serve all -c path/to/hydra/config.yml
# Can also be set using the environment variable:
#   URLS_LOGIN=https://login-app/login
urls:
  login: https://login-app/login
```

ORY Hydra appends a `login_challenge` query parameter to the url. The value is a
ID which should later be used by the Login Endpoint to fetch important
information about the request.

```
https://login-app/login?login_challenge=7bb518c4eec2454dbb289f5fdb4c0ee2
```

### Login Sessions, `prompt`, `max_age`, `id_token_hint`

ORY Hydra keeps track of user sessions. It does so by issuing a cookie which
contains the user ID. On subsequent OAuth2 / OpenID Connect flows, the session
will be checked and the Login Endpoint will be instructed to, for example, show
the Login HTML Form or skip the Login HTML Form.

ORY Hydra supports the following OpenID Connect query parameters:

- `prompt` (optional). Space delimited, case sensitive list of ASCII string
  values that specifies whether the Authorization Server prompts the End-User
  for reauthentication and consent.
  - `prompt=none` instructs ORY Hydra to not display the login or consent user
    interface pages. An error is returned if an End-User is not already
    authenticated or the Client does not have pre-configured consent for the
    requested Claims or does not fulfill other conditions for processing the
    request. The error code will typically be `login_required`,
    `interaction_required`, or another code. This can be used as a method to
    check for existing authentication and/or consent.
  - `prompt=login` instructs ORY Hydra to force the End-User to log in using the
    Login HTML Form in the Login Endpoint.
  - `prompt=consent` instructs ORY Hydra to force the End-User to re-authorize
    (give consent) the OAuth2 Client using the
    [Consent HTML Form in the Consent Endpoint](./consent).
  - `prompt=select_account` is currently not supported in ORY Hydra, see [#].
- `max_age` (optional) specifies the allowable elapsed time in seconds since the
  last time the End-User was actively authenticated by ORY Hydra. If the elapsed
  time is greater than this value, the Login HTML Form must be shown and the
  End-User must re-authenticate.
- `id_token_hint` (optional) - ID Token previously issued by ORY Hydra being
  passed as a hint about the End-User's current or past authenticated session
  with the Client. If the End-User identified by the ID Token is logged in or is
  logged in by the request, then the Authorization Server returns a positive
  response; otherwise, it returns an error, typically `login_required`. It does
  not matter if the ID Token is expired or not.

To specify these parameters add them to the OAuth2 Auth Endpoint URL Query:

```
https://<hydra-public>/oauth2/auth?prompt=login&max_age=60&id_token_hint=...'
```

## The Login Endpoint

The Login Endpoint (set by `urls.login`) is an application written by you. You
can find an exemplary
[NodeJS reference implementation on our GitHub](https://github.com/ory/hydra-login-consent-node).

The Login Endpoint uses the `login_challenge` value in the URL to fetch
information about the login request by making a HTTP GET request to:

```
http(s)://<HYDRA_ADMIN_URL>/oauth2/auth/requests/login?login_challenge=<challenge>
```

The response (see below in "Login Challenge Response" tab) contains information
about the login request. The body contains a `skip` value. If the value is
`false`, the user interface must be shown. If `skip` is true, you should not
show the user interface but instead just accept or reject the login request! For
more details about the implementation check the
["Implementing the Login Endpoint" Guide](../guides/login).

<Tabs
  defaultValue="ui"
  values={[
    {label: 'UI', value: 'ui'},
    {label: 'curl', value: 'curl'},
    {label: 'Login Challenge Response', value: 'json'},
  ]}>
<TabItem value="ui">
<img src={useBaseUrl('/img/docs/login-endpoint.png')}/>
</TabItem>
<TabItem value="curl">

```
curl "http://127.0.0.1:4445/oauth2/auth/requests/login?login_challenge=7bb518c4eec2454dbb289f5fdb4c0ee2"
```

Check the ["Implementing the Login Endpoint" Guide](../guides/login) for
examples using the ORY Hydra SDK in different languages.

</TabItem>
<TabItem value="json">

```json
{
  "challenge": "7bb518c4eec2454dbb289f5fdb4c0ee2",
  "requested_scope": ["openid", "offline"],
  "requested_access_token_audience": null,
  "skip": false,
  "subject": "",
  "oidc_context": {},
  "client": {
    "client_id": "auth-code-client",
    "client_name": "",
    "redirect_uris": ["http://127.0.0.1:5555/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "response_types": ["code", "id_token"],
    "scope": "openid offline",
    "audience": null,
    "owner": "",
    "policy_uri": "",
    "allowed_cors_origins": null,
    "tos_uri": "",
    "client_uri": "",
    "logo_uri": "",
    "contacts": null,
    "client_secret_expires_at": 0,
    "subject_type": "public",
    "token_endpoint_auth_method": "client_secret_basic",
    "userinfo_signed_response_alg": "none",
    "created_at": "2020-07-08T12:31:47Z",
    "updated_at": "2020-07-08T12:31:47Z"
  },
  "request_url": "http://127.0.0.1:4444/oauth2/auth?audience=&client_id=auth-code-client&max_age=0&nonce=hognfveoohhddoralbeygsjg&prompt=&redirect_uri=http%3A%2F%2F127.0.0.1%3A5555%2Fcallback&response_type=code&scope=openid+offline&state=imnweycejbfpyrmnahgqzcmm",
  "session_id": "d3c98aa6-67ae-478b-bc30-f7887b58f630"
}
```

</TabItem>
</Tabs>

The way you authenticate the End-User is up to you. In most cases, you will show
an HTML form similar to:

```html
<form action="/login" method="post">
  <input type="hidden" name="csrf_token" value="...." />
  <!-- Use CSRF tokens in your HTML forms! -->
  <input
    type="email"
    name="login_email"
    placeholder="Please enter your email address to log in"
  />
  <input type="password" name="login_password" />
  <input type="checkbox" name="remember" value="Remember me on this device" />
  <input type="submit" value="Log in" />
</form>
```

Once the End-User authenticated successfully, you either **accept** the login
challenge, or you **reject** (e.g. the user is not allowed to perform OAuth2
flows) the login challenge.

### Accepting the Login Flow

To accept the Login Challenge, make a HTTP PUT request with
`Content-Type: application/json` and a JSON payload (see
[Accept Login Request HTTP API Reference](../reference/api#schemaacceptloginrequest))

:::warning

The subject must be an immutable user ID, it should never be an email address, a
username, or something else that may change over time.

:::

```json
{
  // Subject is the user ID of the end-user that authenticated.
  "subject": "string", // required!

  // All values below are optional!

  // Remember, if set to true, tells ORY Hydra to remember this user by telling the user agent (browser) to store
  // a cookie with authentication data. If the same user performs another OAuth 2.0 Authorization Request, he/she will not be asked to log in again.
  "remember": true,

  // RememberFor sets how long the authentication should be remembered for in seconds. If set to 0,
  // the authorization will be remembered for the duration of the browser session (using a session cookie).
  "remember_for": 0,

  // ACR sets the Authentication AuthorizationContext Class Reference value for this authentication session. You can use it to express that, for example, a user authenticated using two factor authentication.
  "acr": "string",

  // Context is an optional object which can hold arbitrary data. The data will be made available when fetching the
  // consent request under the "context" field. This is useful in scenarios where login and consent endpoints share
  // data.
  "context": {
    // "foo": "bar"
  },

  // ForceSubjectIdentifier forces the "pairwise" user ID of the end-user that authenticated. The "pairwise"
  // user ID refers to the (Pairwise Identifier Algorithm)[http://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg]
  // of the OpenID Connect specification. It allows you to set an obfuscated subject ("user") identifier that is unique
  // to the client. Please note that this changes the user ID on endpoint /userinfo and sub claim of the ID Token.
  // It does not change the sub claim in the OAuth 2.0 Introspection. Per default, ORY Hydra handles this value with its own algorithm.
  // In case you want to set this yourself you can use this field. Please note that setting this field has no effect if pairwise is not
  // configured in ORY Hydra or the OAuth 2.0 Client does not expect a pairwise identifier (set via subject_type key in the client's configuration).
  // Please also be aware that ORY Hydra is unable to properly compute this value during authentication. This implies that
  // you have to compute this value on every authentication process (probably depending on the client ID or some other unique value).
  // If you fail to compute the proper value, then authentication processes which have id_token_hint set might fail.
  "force_subject_identifier": "string"
}
```

With `curl` this might look like the following request:

```shell script
$ curl --location --request PUT 'http://127.0.0.1:4445/oauth2/auth/requests/login/accept?login_challenge=7bb518c4eec2454dbb289f5fdb4c0ee2' \
--header 'Content-Type: application/json' \
--data-raw '{
    "subject": "the-user-id-that-just-logged-in",
    "remember": true,
    "remember_for": 3600
}'
```

The server responds with JSON

```
{
  "redirect_to": "http://127.0.0.1:4445/oauth2/auth..."
}
```

which is the URL your application must redirect the End-User's browser to.

Check the ["Implementing the Login Endpoint" Guide](../guides/login) for
examples using the ORY Hydra SDK in different languages.

### Rejecting the Login Flow

To reject the Login Challenge, make a HTTP PUT request with
`Content-Type: application/json` and a JSON payload (see
[Reject Login Request HTTP API Reference](../reference/api#schemarejectrequest))

```json
{
  // The error should follow the OAuth2 error format (e.g. `invalid_request`, `login_required`).
  "error": "user_banned",

  // Description of the error in a human readable format.
  "error_description": "You are banned!",

  // Hint to help resolve the error.
  "error_hint": "Contact the site administrator.",

  // Debug contains information to help resolve the problem as a developer. Usually not exposed
  // to the public but only in the server logs.
  "error_debug": "The user was marked banned in the database.",

  // Represents the HTTP status code of the error (e.g. 401 or 403)
  //
  // Defaults to 400
  "status_code": 403
}
```

With `curl` this might look like the following request:

```shell script
$ curl --location --request PUT 'http://127.0.0.1:4445/oauth2/auth/requests/login/reject?login_challenge=7bb518c4eec2454dbb289f5fdb4c0ee2' \
--header 'Content-Type: application/json' \
--data-raw '{
  "error": "user_banned",
  "error_debug": "The user was marked banned in the database.",
  "error_description": "You are banned!",
  "error_hint": "Contact the site administrator.",
  "status_code": 403
}'
```

The server responds with JSON

```json
{
  "redirect_to": "http://127.0.0.1:4445/oauth2/auth..."
}
```

which is the URL your application must the End-User's browser to.

Check the ["Implementing the Login Endpoint" Guide](../guides/login) for
examples using the ORY Hydra SDK in different languages.

## Redirection to the Consent Endpoint

Please head over to [Consent Flow](./consent)!

## Revoking ORY Hydra Login Sessions

Revoking a login session will remove all of the user's cookies at ORY Hydra and
will require the user to re-authenticate when performing the next OAuth 2.0
Authorize Code Flow. Be aware that this option will remove all cookies from all
devices.

:::info

Revoking a login session does not invalidate any Access, Refresh, or ID Tokens!
If you log out of GitHub, you will not be logged out of CircleCI/TravisCI.

:::

Revoking the login sessions of a user is as easy as sending `DELETE` to
`/oauth2/auth/sessions/login?subject={subject}` (see
[full API documentation](../reference/api#opIdrevokeAuthenticationSession)).

This endpoint is not compatible with OpenID Connect Front-/Backchannel logout
and does not revoke any tokens.
